home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Devices and Hardware / CD ROM / CD-ROM Detection / CDROMDetection.c < prev   
Encoding:
C/C++ Source or Header  |  2000-09-28  |  8.0 KB  |  273 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        CDROMDetection.c
  3.     
  4.     Description:The sample shows how to determine whether a drive is a CD-ROM drive.
  5.  
  6.     Author:        BB
  7.  
  8.     Copyright:     Copyright: © 1998,1999 by Apple Computer, Inc.
  9.                 all rights reserved.
  10.     
  11.     Disclaimer:    You may incorporate this sample code into your applications without
  12.                 restriction, though the sample code has been provided "AS IS" and the
  13.                 responsibility for its operation is 100% yours.  However, what you are
  14.                 not permitted to do is to redistribute the source as "DSC Sample Code"
  15.                 after having made changes. If you're going to re-distribute the source,
  16.                 we require that you make it clear in the source that the code was
  17.                 descended from Apple Sample Code, but that you've made changes.
  18.     
  19.     Change History (most recent first):
  20.                 6/23/99 Updated for Metrowerks Codwarrior Pro 2.1(KG)
  21.  
  22. */
  23.  
  24. #include <TextUtils.h>
  25. #include <LowMem.h>
  26. #include <DriverGestalt.h>
  27. #include <Files.h>
  28. #include <Devices.h>
  29. #include <SCSI.h>
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <SIOUX.h>        // Metrowerks only
  34.  
  35. // Be sure and put the #pragma options align=mac68k statement
  36. // around any structure definitions which require a particular
  37. // structure alignment; otherwise the compiler tries to word
  38. // align the definitions, and nothing works on the PowerPC side.
  39. #if PRAGMA_ALIGN_SUPPORTED
  40. #pragma options align=mac68k
  41. #endif
  42.  
  43. struct DeviceIdentParam {
  44.     QElemPtr                        qLink;
  45.     short                            qType;
  46.     short                            ioTrap;
  47.     Ptr                                ioCmdAddr;
  48.     IOCompletionUPP                    ioCompletion;
  49.     OSErr                            ioResult;
  50.     StringPtr                        ioNamePtr;
  51.     short                            ioVRefNum;
  52.     short                            ioCRefNum;
  53.     short                            csCode;
  54.     DeviceIdent                        deviceIdentification;
  55.     short                            csParam[9];
  56. };
  57. typedef struct DeviceIdentParam DeviceIdentParam, *DeviceIdentParamPtr;
  58.  
  59. #if PRAGMA_ALIGN_SUPPORTED
  60. #pragma options align=reset
  61. #endif
  62.  
  63. // This declares in C a type called "CallForEveryDriveQueueElement"
  64. // which can then be declared as a variable in some other routine.
  65. // That routine can initialize the variable to the address of some
  66. // routine to call, and pass that as a parameter to CruiseDriveQueue.
  67. typedef pascal OSErr (*CallForEveryDriveQueueElement)(DrvQElPtr dqPtr);
  68. // to use the above declaration, you would have code such as this:
  69. //        CallForEveryDriveQueueElement someCall = YourRoutineName;
  70. //        CruiseDriveQueue(someCall);
  71. // where "YourRoutineName" is replaced by the name of a routine
  72. // which has been declared as follows:
  73. //         pascal OSErr YourRoutineName(DrvQElPtr dqPtr);
  74. //
  75. // This is the declaration of the routine which cruises the drive
  76. // queue, calling the input parameter (a procedure) with each drive 
  77. // queue element in the drive queue.  It looks complicated, but
  78. // it winds up being much easier to use.
  79. pascal OSErr CruiseDriveQueue(CallForEveryDriveQueueElement theCall);
  80.  
  81. void            DetectCD(void);
  82. OSErr            DeviceIdentification(
  83.                     StringPtr drvrNamePtr, 
  84.                     DrvQElPtr dqPtr, 
  85.                     DeviceIdent *d);
  86. pascal OSErr    PrintDriverInformation(DrvQElPtr dqPtr);
  87. StringPtr        DrvrRefToName(short refNum);
  88. OSErr             DetermineUsingDriverGestalt(
  89.                     short driverRefNum,
  90.                     short driveNumber,
  91.                     OSType *deviceType);
  92.  
  93. //-----------------------------------------------------------------
  94. // The main routine.  Start here.  We turn off the annoying
  95. // "Do you want to save this window?" option of Metrowerks
  96. // Standard Libraries
  97. //
  98. void main(void)
  99. {
  100.     SIOUXSettings.asktosaveonclose = false;        // Metrowerks only
  101.     
  102.     printf ("Sample showing how to detect CD-ROM drives\n\n");
  103.  
  104.     DetectCD();
  105. }
  106.  
  107. //-----------------------------------------------------------------
  108. // This is the declaration of the routine which cruises the drive
  109. // queue, calling the input parameter (a procedure) with each drive
  110. // queue element in the drive queue.  It looks complicated, but it
  111. // winds up being easy to use.
  112. //
  113. pascal OSErr CruiseDriveQueue(CallForEveryDriveQueueElement theCall)
  114. {
  115.     register DrvQElPtr    dqPtr;
  116.     OSErr                err;
  117.  
  118.     dqPtr = (DrvQElPtr) GetDrvQHdr()->qHead;
  119.  
  120.     while (dqPtr != NULL) 
  121.     {
  122.         err = theCall(dqPtr);
  123.         if (err)
  124.             break;
  125.         dqPtr = (DrvQEl *) dqPtr->qLink;
  126.     }
  127.     return (err);
  128. }
  129.  
  130. //-----------------------------------------------------------------
  131. // This routine returns the device identification as documented 
  132. // in Designing PCI Cards and Drivers
  133. //
  134. OSErr    DeviceIdentification( StringPtr drvrNamePtr, 
  135.                               DrvQElPtr dqPtr, 
  136.                               DeviceIdent *d)
  137. {
  138.     DeviceIdentParam    pb = {0};
  139.     OSErr                err;
  140.     
  141.     pb.ioCompletion = nil;
  142.     pb.ioNamePtr = drvrNamePtr;
  143.     err = PBOpenSync((ParmBlkPtr)&pb);
  144.  
  145.     if (!err)
  146.     {
  147.         pb.ioVRefNum = dqPtr -> dQDrive;
  148.         pb.ioCRefNum = dqPtr -> dQRefNum;
  149.         pb.csCode = 120;
  150.         err = PBStatusSync((ParmBlkPtr)&pb);
  151.     }
  152.     *d = pb.deviceIdentification;
  153.     return err;
  154. }
  155.  
  156. //-----------------------------------------------------------------
  157. // This routine just sets up a variable with the name of a routine
  158. // to call for every drive queue element, and then calls our
  159. // generic "scan the drive queue" routine.  This will call the
  160. // routine we passed in for every drive queue element.
  161. // We tell the "CruiseDriveQueue" routine to call our 
  162. // PrintDriverInformation routine for each entry in the drive queue.
  163. void DetectCD(void)
  164. {
  165.     CallForEveryDriveQueueElement someCall = PrintDriverInformation;
  166.     CruiseDriveQueue(someCall);
  167. }
  168.  
  169. //-----------------------------------------------------------------
  170. // PrintDriverInformation prints information about the driver for
  171. // each Drive Queue Element we pass it.  If the drive in question
  172. // passes tests to see if it's a CD-ROM drive, we print additional
  173. // information
  174. //
  175. pascal OSErr PrintDriverInformation(DrvQElPtr dqPtr)
  176. {
  177.     StringPtr    drvrNamePtr;
  178.     OSType        theDriveType;
  179.     DeviceIdent    d;
  180.     OSErr        err;
  181.     
  182.     // dqPtr->dQRefNum contains the driver reference number.  
  183.     // In order to display something to the user, we will get
  184.     // the driver name by looking in the unit table (an array)
  185.     // to find the driver name.
  186.     drvrNamePtr = DrvrRefToName(dqPtr->dQRefNum);
  187.  
  188.     printf("DriverName: %.*s ", drvrNamePtr[0], &drvrNamePtr[1]);
  189.     if ( EqualString(drvrNamePtr, "\p.AppleCD", false, true) )
  190.         printf("(This is a CD-ROM drive.) ");
  191.     
  192.     err = DetermineUsingDriverGestalt(dqPtr->dQRefNum, dqPtr->dQDrive, &theDriveType);
  193.     if (!err)
  194.     {
  195.         char c[5];
  196.         BlockMoveData(&theDriveType, c, 4);
  197.         c[4] = 0;
  198.         printf("Driver Gestalt returned '%s'", c);
  199.     }
  200.     
  201.     err = DeviceIdentification(drvrNamePtr, dqPtr, &d);
  202.     if (!err)
  203.     {
  204.         printf("\nDevice reports that it is bus type %d, bus %d, target %d, partition/LUN %d.",
  205.             d.diReserved, d.bus, d.targetID, d.LUN);
  206.     }
  207.     printf("\n");
  208.     return noErr;
  209. }
  210.  
  211. //-----------------------------------------------------------------
  212. // Lookup driver name from the unit table. The driver name starts
  213. // at 18 bytes into the driver itself.  From the Unit Table entry
  214. // for this driver, get the name, but take into account whether it
  215. // is a handle based driver or a pointer based driver.
  216. //
  217. StringPtr DrvrRefToName(short refNum)
  218. {
  219.     AuxDCEHandle*        UTable  = (AuxDCEHandle*) LMGetUTableBase();
  220.     DCtlPtr                dctl;
  221.     Ptr                    p;
  222.     static StringPtr    driverName;
  223.     
  224.     if ( refNum == 0 )
  225.     {
  226.         driverName = "\p<none>";
  227.     }
  228.     else
  229.     {
  230.         dctl = (DCtlPtr) *UTable[~refNum];
  231.         p      =  dctl->dCtlDriver;
  232.         
  233.         // a RAMbased driver is handle based, a ROMbased driver
  234.         // is pointer based.  If it's a handle based driver, we
  235.         // need one more level of indirection.  The following 
  236.         // test provides that indirection if necessary.
  237.         if( dctl->dCtlFlags  & dRAMBasedMask) 
  238.             p = (void*) *p;
  239.  
  240.         if ( p != nil )
  241.             driverName = (void *)(p+18);
  242.         else
  243.             driverName = "\p-Purged-";
  244.     }
  245.     return  ( driverName);
  246. }
  247.  
  248. //-----------------------------------------------------------------
  249. // Call the driver using the DriverGestalt status code.  The result
  250. // tells us if this driver is a CD-ROM
  251. //
  252. OSErr DetermineUsingDriverGestalt(short driverRefNum, 
  253.                                   short driveNumber, 
  254.                                   OSType *deviceType)
  255. {
  256.     DriverGestaltParam    pb;
  257.     OSErr                err;
  258.     
  259.     pb.ioVRefNum             = driveNumber;
  260.     pb.ioCRefNum            = driverRefNum;
  261.     pb.csCode                 = kDriverGestaltCode;
  262.     pb.driverGestaltSelector = kdgDeviceType;
  263.     
  264.     err = PBStatusSync((ParmBlkPtr) &pb);
  265.     
  266.     if (!err)
  267.     {
  268.         *deviceType = pb.driverGestaltResponse;
  269.     }
  270.     return (err);
  271. }
  272.  
  273.